import os

from workload.workloads_manager import WorkloadManager
from common.benchmark_var import GlobalEnv
from utils.executor import Executor
from framework.native_workload import NativeWorkload
from common.benchmark_var import MeasureUnit


class GlperfbenchWorkload(NativeWorkload):
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = ''
        self.lang = 'C'
        self.description = ''
        self.result_file_name = ''
        self.desc = ''
        self.TMPDIR = os.path.join(self.src_dir, 'tmp')
        self.program_options = ""
        self.support_multi_instance = False
        # self.exe = os.path.join(self.bin_dir,'GPU-perf')
        self.exe = ""
        self.valid = True
        self.sub_item_metric = {
            "depth": {
                "desc": "OpenGL: depth",
                "unit": MeasureUnit.FPS,
            },
            "fire": {
                "desc": "OpenGL: fire",
                "unit": MeasureUnit.FPS,
            },
            "fog": {
                "desc": "OpenGL: fog",
                "unit": MeasureUnit.FPS,
            },
            "instance": {
                "desc": "OpenGL: instance",
                "unit": MeasureUnit.FPS,
            },
            "material": {
                "desc": "OpenGL: material",
                "unit": MeasureUnit.FPS,
            },
            "msaa": {
                "desc": "OpenGL: msaa",
                "unit": MeasureUnit.FPS,
            },
            "sprite": {
                "desc": "OpenGL: sprite",
                "unit": MeasureUnit.FPS,
            },
            "skybox": {
                "desc": "OpenGL: skybox",
                "unit": MeasureUnit.FPS,
            },
            "terrain": {
                "desc": "OpenGL: terrain",
                "unit": MeasureUnit.FPS,
            },
            "textures": {
                "desc": "OpenGL: textures",
                "unit": MeasureUnit.FPS,
            },
            "pixel": {
                "desc": "OpenGL: pixel",
                "unit": MeasureUnit.FPS,
            },
            "fill": {
                "desc": "OpenGL: fill",
                "unit": MeasureUnit.FPS,
            },
            "shader": {
                "desc": "OpenGL: shader",
                "unit": MeasureUnit.FPS,
            },
            "mesh": {
                "desc": "OpenGL: mesh",
                "unit": MeasureUnit.FPS,
            },
            "shadowmap": {
                "desc": "OpenGL: shadowmap",
                "unit": MeasureUnit.FPS,
            },
            "lights":{
                "desc": "OpenGL: lights",
                "unit": MeasureUnit.FPS,
            },
            "computeshader":{
                "desc": "OpenGL: computeshader",
                "unit": MeasureUnit.FPS,
            },
            "feedback":{
                "desc": "OpenGL: feedback",
                "unit": MeasureUnit.FPS,
            },
            "waterwave":{
                "desc": "OpenGL: waterwave",
                "unit": MeasureUnit.FPS,
            },
        }

    def get_instance_cmd(self, instance):
        executors = []
        cmd = "bash {}".format(self.program_options)
        executor = Executor(desc=self.desc,
                            command=cmd,
                            debug=self.debug,
                            exec_dir=instance.instance_dir)
        executors.append(executor)
        return executors

    def get_raw_score(self, instance):
        result_file = os.path.join(instance.instance_dir, self.result_file_name)
        if not os.path.exists(result_file):
            return 0
        with open(result_file, 'r') as f:
            lines = f.readlines()
            for i in range(len(lines)):
                score_line = lines[i].strip()
                if score_line.find('|') != -1:
                    str_list = score_line.split('|')
                    score = float(str_list[1])
                    return score
        return 0

    def setup_dir(self):
        self.work_dir = os.path.join(GlobalEnv.GCBS_WORKLOAD_DIR, "glperfbench")
        self.src_dir = os.path.join(self.work_dir, 'src')
        self.build_dir = os.path.join(self.work_dir, 'build')
        self.data_dir = os.path.join(self.work_dir, 'data')
        self.log_dir = os.path.join(self.work_dir, 'log')
        self.bin_dir = os.path.join(self.work_dir, 'bin')
        self.run_dir = os.path.join(self.work_dir, 'run', self.name)
        dir_list = [self.work_dir, self.src_dir, self.build_dir, self.data_dir,
                    self.log_dir, self.run_dir, self.bin_dir]
        for directory in dir_list:
            if not os.path.exists(directory):
                os.makedirs(directory)

@WorkloadManager.register_workload('gl_lights')
class GlLightsWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: lights"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = "gl_lights"
        self.description = GlLightsWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_lights.log"
        self.program_options = "%s/glperf.sh -b lights"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_lights"

@WorkloadManager.register_workload('gl_computeshader')
class GlComputeshaderWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: computeshader"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = "gl_computeshader"
        self.description = GlComputeshaderWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_computeshader.log"
        self.program_options = "%s/glperf.sh -b computeshader"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_computeshader"

@WorkloadManager.register_workload('gl_feedback')
class GlFeedbackWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: feedback"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = "gl_feedback"
        self.description = GlFeedbackWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_feedback.log"
        self.program_options = "%s/glperf.sh -b feedback"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_feedback"

@WorkloadManager.register_workload('gl_depth')
class GlDepthWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: depth"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = "gl_depth"
        self.description = GlDepthWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_depth.log"
        self.program_options = "%s/glperf.sh -b depth"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_depth"

@WorkloadManager.register_workload('gl_fire')
class GlFireWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: fire"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_fire'
        self.description = GlFireWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_fire.log"
        self.program_options = "%s/glperf.sh -b fire"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_fire"

@WorkloadManager.register_workload('gl_fog')
class GlFogWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: fog"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_fog'
        self.description = GlFogWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_fog.log"
        self.program_options = "%s/glperf.sh -b fog"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_fog"

@WorkloadManager.register_workload('gl_material')
class GlMaterialWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: material"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_material'
        self.description = GlMaterialWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_material.log"
        self.program_options = "%s/glperf.sh -b material"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_material"

@WorkloadManager.register_workload('gl_msaa')
class GlMsaaWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: msaa"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_msaa'
        self.description = GlMsaaWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_msaa.log"
        self.program_options = "%s/glperf.sh -b msaa"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_msaa"

@WorkloadManager.register_workload('gl_sprite')
class GlSpriteWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: sprite"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_sprite'
        self.description = GlSpriteWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_sprite.log"
        self.program_options = "%s/glperf.sh -b sprite"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_sprite"

@WorkloadManager.register_workload('gl_skybox')
class GlSkyboxWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: skybox"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_skybox'
        self.description = GlSkyboxWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_skybox.log"
        self.program_options = "%s/glperf.sh -b skybox" % self.work_dir
        self.setup_dir()
        self.desc = "gl_skybox"

@WorkloadManager.register_workload('gl_terrain')
class GlTerrainWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: terrain"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_terrain'
        self.description = GlTerrainWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_terrain.log"
        self.program_options = "%s/glperf.sh -b terrain"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_terrain"

@WorkloadManager.register_workload('gl_textures')
class GlTexturesWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: textures"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_textures'
        self.description = GlTexturesWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_textures.log"
        self.program_options = "%s/glperf.sh -b textures"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_textures"

@WorkloadManager.register_workload('gl_pixel')
class GlPixelWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: pixel"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_pixel'
        self.description = GlPixelWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_pixel.log"
        self.program_options = "%s/glperf.sh -b pixel"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_pixel"

@WorkloadManager.register_workload('gl_fill')
class GlFillWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: fill"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_fill'
        self.description = GlFillWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_fill.log"
        self.program_options = "%s/glperf.sh -b fill"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_fill"

@WorkloadManager.register_workload('gl_shader')
class GlShaderWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: shader"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_shader'
        self.description = GlShaderWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_shader.log"
        self.program_options = "%s/glperf.sh -b shader"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_shader"

@WorkloadManager.register_workload('gl_mesh')
class GlMeshWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: mesh"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_mesh'
        self.description = GlMeshWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_mesh.log"
        self.program_options = "%s/glperf.sh -b mesh"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_mesh"

@WorkloadManager.register_workload('gl_shadowmap')
class GlShadowmapWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: shadowmap"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_shadowmap'
        self.description = GlShadowmapWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_shadowmap.log"
        self.program_options = "%s/glperf.sh -b shadowmap"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_shadowmap"

@WorkloadManager.register_workload('gl_instance')
class GlInstanceWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: instance"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_instance'
        self.description = GlInstanceWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_instance.log"
        self.program_options = "%s/glperf.sh -b instance"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_instance"

@WorkloadManager.register_workload('gl_waterwave')
class GlWaterwaveWorkload(GlperfbenchWorkload):
    DESC = "OpenGL: waterwave"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = 'gl_waterwave'
        self.description = GlWaterwaveWorkload.DESC
        self.unit_of_measure = MeasureUnit.FPS
        self.result_file_name = "gl_waterwave.log"
        self.program_options = "%s/glperf.sh -b waterwave"%(self.work_dir)
        self.setup_dir()
        self.desc = "gl_waterwave"

@WorkloadManager.register_workload('glperf')
class GlperfWorkload(GlperfbenchWorkload):
    DESC = "Glperf All"
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.name = "glperf"
        self.description = GlperfWorkload.DESC
        self.unit_of_measure = MeasureUnit.SCORE
        self.dists = {"depth":"GlDepthWorkload(name, options, baseline)",
        "fire":"GlFireWorkload(name, options, baseline)",
        "fog":"GlFogWorkload(name, options, baseline)",
        "instance":"GlInstanceWorkload(name, options, baseline)",
        "material":"GlMaterialWorkload(name, options, baseline)",
        "msaa":"GlMsaaWorkload(name, options, baseline)",
        "sprite":"GlSpriteWorkload(name, options, baseline)",
        "skybox":"GlSkyboxWorkload(name, options, baseline)",
        "terrain":"GlTerrainWorkload(name, options, baseline)",
        "textures":"GlTexturesWorkload(name, options, baseline)",
        "pixel":"GlPixelWorkload(name, options, baseline)",
        "fill":"GlFillWorkload(name, options, baseline)",
        "shader":"GlShaderWorkload(name, options, baseline)",
        "mesh":"GlMeshWorkload(name, options, baseline)",
        "shadowmap":"GlShadowmapWorkload(name, options, baseline)",
        "lights":"GlLightsWorkload(name, options, baseline)",
        "computeshader":"GlComputeshaderWorkload(name, options, baseline)",
        "feedback":"GlFeedbackWorkload(name, options, baseline)",
        "waterwave":"GlWaterwaveWorkload(name, options, baseline)"}  
        for key in self.dists:
            setattr(self,key,eval(self.dists[key]))

    def get_instance_cmd(self, instance):
        executors = []
        for key  in  self.dists:
            executors.extend(getattr(self,key).get_instance_cmd(instance))
        return executors

    def get_raw_score(self, instance):
        score_dict = {}
        score_value = 1
        for key  in  self.dists:
            score_dict[key] = getattr(self,key).get_raw_score(instance)
        for value in score_dict.values():
            score_value = score_value * value
        score_all = pow(score_value,1/len(score_dict))
        score = {"score": score_all,"sub_item":score_dict}
        return score
